package com.ccx.demo.business.common.service;

import com.ccx.demo.business.common.dao.jpa.ErrorLogRepository;
import com.ccx.demo.business.common.dto.TabErrorLogInsertDTO;
import com.ccx.demo.business.common.dto.TabErrorLogUpdateDTO;
import com.ccx.demo.business.common.entity.TabErrorLog;
import com.querydsl.core.QueryResults;
import com.support.mvc.entity.base.Page;
import com.support.mvc.exception.DeleteRowsException;
import com.support.mvc.exception.UpdateRowsException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;

import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.*;
import java.util.stream.Collectors;

//import static com.ccx.demo.config.init.AppInit.getCacheManager; // 若使用缓存需要解开代码

/**
 * 服务接口实现类：异常日志记录
 *
 * @author 谢长春 on 2022-02-16 V20220301
 */
@Slf4j
@Service
@Validated
@RequiredArgsConstructor
public class ErrorLogService
//      , ITabErrorLogCache
{
    private final ErrorLogRepository repository;
//     /** // 若使用缓存需要解开代码
//      * 获取当前缓存管理器，用于代码控制缓存
//      *
//      * @return {@link Cache}
//      */
//     public Cache getCache() {
//         return Objects.requireNonNull(getCacheManager().getCache(CACHE_ROW_BY_ID), "未获取到缓存管理对象:".concat(CACHE_ROW_BY_ID));
//     }
//
//     /** // 若使用缓存需要解开代码
//      * 清除多个 key 对应的缓存
//      *
//      * @param ids {@link TabErrorLog#getId()}
//      */
//     public void clearKeys(final Collection<Long> ids) {
//         ids.stream().distinct().forEach(id -> getCache().evict(id));
//     }

    /**
     * 新增 异常日志记录
     *
     * @param dto    {@link TabErrorLogInsertDTO} 实体对象
     * @param userId {@link Long} 操作用户ID
     * @return {@link TabErrorLog} 实体对象
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public @NotNull(message = "返回值不能为null") TabErrorLog insert(
            @Valid @NotNull(message = "【dto】不能为null") final TabErrorLogInsertDTO dto
            , @NotNull(message = "【userId】不能为null") final Long userId) {
        final TabErrorLog obj = new TabErrorLog();
        BeanUtils.copyProperties(dto, obj);
        return repository.insert(userId, obj);
    }

    /**
     * 批量新增 异常日志记录
     *
     * @param list   {@link List<TabErrorLogInsertDTO>}  实体对象集合
     * @param userId {@link Long} 操作用户ID
     * @return List<TabErrorLog> 实体对象集合
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public @NotNull(message = "返回值不能为null") List<TabErrorLog> insert(
            @NotEmpty(message = "【list】不能为空") final List<@Valid @NotNull TabErrorLogInsertDTO> list
            , @NotNull(message = "【userId】不能为null") final Long userId) {
        return repository.insert(userId, list.stream()
                .map(dto -> {
                    final TabErrorLog obj = new TabErrorLog();
                    BeanUtils.copyProperties(dto, obj);
                    return obj;
                })
                .collect(Collectors.toList())
        );
    }

    /**
     * 更新 异常日志记录 ；
     *
     * @param id     {@link Long} 数据ID
     * @param userId {@link Long} 操作用户ID
     * @param dto    {@link TabErrorLogUpdateDTO} 实体对象
     */
    @Transactional(rollbackFor = Exception.class)
    public void update(
            @NotNull(message = "【id】不能为null") @Positive(message = "【id】必须大于0") final Long id
            , @NotNull(message = "【userId】不能为null") final Long userId
            , @Valid @NotNull(message = "【dto】不能为null") final TabErrorLogUpdateDTO dto) {
        final TabErrorLog obj = new TabErrorLog();
        BeanUtils.copyProperties(dto, obj);
        UpdateRowsException.asserts(repository.update(id, userId, obj));
    }

//    /**
//     * 异常日志记录 按ID删除，物理删除
//     *
//     * @param id     {@link Long} 数据ID
//     * @param userId {@link Long} 操作用户ID
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void deleteById(
//            @NotNull(message = "【id】不能为null") @Positive(message = "【id】必须大于0") final Long id
//            ,@NotNull(message = "【userId】不能为null") final Long userId) {
//        DeleteRowsException.asserts(repository.deleteById(id, userId));
//    }
//
//    /**
//     * 异常日志记录 按 id+updateTime 删除，物理删除
//     *
//     * @param id         {@link Long} 数据ID
//     * @param updateTime {@link String} 最后一次更新时间
//     * @param userId {@link Long} 操作用户ID
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void deleteById(
//            @NotNull(message = "【id】不能为null") @Positive(message = "【id】必须大于0") final Long id
//            , @NotBlank(message = "【updateTime】不能为null") @Size(min = 17, max = 17, message = "【updateTime】必须是 17 位") final String updateTime
//            ,@NotNull(message = "【userId】不能为null") final Long userId
//    ) {
//        DeleteRowsException.asserts(repository.deleteById(id, updateTime, userId));
//    }
//
//    /**
//     * 异常日志记录 按ID删除，物理删除
//     *
//     * @param ids     {@link Set<Long>} 数据ID
//     * @param userId {@link Long} 操作用户ID
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void deleteByIds(
//            @NotEmpty(message = "【ids】不能为空") final Set<@Valid @NotNull Long> ids
//            ,@NotNull(message = "【userId】不能为null") final Long userId) {
//        DeleteRowsException.asserts(repository.deleteByIds(ids, userId));
//        // clearKeys(ids); // 若使用缓存需要解开代码
//    }
//
//    /**
//     * 异常日志记录 按 id+updateTime 删除，物理删除
//     *
//     * @param ids     {@link Set<Long>} 数据ID
//     * @param updateTimes     {@link Set<String>} 最后一次更新时间
//     * @param userId {@link Long} 操作用户ID
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void deleteByIds(
//            @NotEmpty(message = "【ids】不能为空") final Set<@Valid @NotNull Long> ids
//            , @NotEmpty(message = "【updateTimes】不能为空") final Set<@Valid @NotBlank String> updateTimes
//            ,@NotNull(message = "【userId】不能为null") final Long userId
//    ) {
//        DeleteRowsException.asserts(repository.deleteByIds(ids, updateTimes, userId));
//        // clearKeys(ids); // 若使用缓存需要解开代码
//    }
//

    /**
     * 异常日志记录 按ID删除，逻辑删除
     *
     * @param id     {@link Long} 数据ID
     * @param userId {@link Long} 操作用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void markDeleteById(
            @NotNull(message = "【id】不能为null") @Positive(message = "【id】必须大于0") final Long id
            , @NotNull(message = "【userId】不能为null") final Long userId) {
        DeleteRowsException.asserts(repository.markDeleteById(id, userId));
    }

    /**
     * 异常日志记录 按 id+updateTime 删除，逻辑删除
     *
     * @param id         {@link Long} 数据ID
     * @param updateTime {@link String} 最后一次更新时间
     * @param userId     {@link Long} 操作用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void markDeleteById(
            @NotNull(message = "【id】不能为null") @Positive(message = "【id】必须大于0") final Long id
            , @NotBlank(message = "【updateTime】不能为null") @Size(min = 17, max = 17, message = "【updateTime】必须是 17 位") final String updateTime
            , @NotNull(message = "【userId】不能为null") final Long userId
    ) {
        DeleteRowsException.asserts(repository.markDeleteById(id, updateTime, userId));
    }

    /**
     * 异常日志记录 按ID删除，逻辑删除
     *
     * @param ids    {@link Set<Long>} 数据ID
     * @param userId {@link Long} 操作用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void markDeleteByIds(
            @NotEmpty(message = "【ids】不能为空") final Set<@Valid @NotNull Long> ids
            , @NotNull(message = "【userId】不能为null") final Long userId) {
        DeleteRowsException.asserts(repository.markDeleteByIds(ids, userId), ids.size());
        // clearKeys(ids); // 若使用缓存需要解开代码
    }

    /**
     * 异常日志记录 按 id+updateTime 删除，逻辑删除
     *
     * @param ids         {@link Set<Long>} 数据ID
     * @param updateTimes {@link Set<String>} 最后一次更新时间
     * @param userId      {@link Long} 操作用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void markDeleteByIds(
            @NotEmpty(message = "【ids】不能为空") final Set<@Valid @NotNull Long> ids
            , @NotEmpty(message = "【updateTimes】不能为空") final Set<@Valid @NotBlank String> updateTimes
            , @NotNull(message = "【userId】不能为null") final Long userId
    ) {
        DeleteRowsException.asserts(repository.markDeleteByIds(ids, updateTimes, userId), ids.size());
        // clearKeys(ids); // 若使用缓存需要解开代码
    }

    /**
     * 异常日志记录 按ID查询对象，注意这里可能有 deleted 为 YES 的数据
     *
     * @param id {@link Long} 数据ID
     * @return {@link Optional<TabErrorLog>} 实体对象
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public Optional<TabErrorLog> findById(final Long id) {
        if (Objects.isNull(id) || id < 1) {
            return Optional.empty();
        }
        return repository.findById(id)
                .map(TabErrorLog::cloneObject); // 必须要 clone ，如果直接对持久化对象调用 set 方法，会触发更新动作
//         return Optional.ofNullable(repository.findCacheById(id)).map(TabErrorLog::cloneObject); // 若使用缓存需要解开代码
    }

    /**
     * 异常日志记录 按条件分页查询列表
     *
     * @param condition {@link TabErrorLog} 查询条件
     * @param page      {@link Page} 分页排序集合
     * @return {@link QueryResults<TabErrorLog>} 分页对象
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public @NotNull(message = "返回值不能为null") QueryResults<TabErrorLog> page(
            @NotNull(message = "【condition】不能为null") final TabErrorLog condition,
            @NotNull(message = "【page】不能为null") @Valid final Page page) {
        return repository.page(condition, page);
    }

//// 非必要情况下不要开放列表查询方法，因为没有分页控制，容易内存溢出。大批量查询数据应该使用分页查询
//    /**
//     * 异常日志记录 按条件查询列表
//     *
//     * @param condition {@link TabErrorLog} 查询条件
//     * @return {@link List<TabErrorLog>} 结果集合
//     */
//    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
//    public @NotNull(message = "返回值不能为null") List<TabErrorLog> list(
//            @NotNull(message = "【condition】不能为null") final TabErrorLog condition) {
//        return repository.list(condition);
//    }
//

    /**
     * 异常日志记录 按 id 批量查询列表，注意这里可能有 deleted 为 true 的数据
     *
     * @param ids {@link Long}  数据 id 集合
     * @return {@link List<TabErrorLog>} 结果集合
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public @NotNull(message = "返回值不能为null") List<TabErrorLog> listByIds(final Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return repository.listByIds(ids);
    }

    /**
     * 异常日志记录 按 id 批量查询列表，返回 map ， key 为数据 id ， 注意这里可能有 deleted 为 true 的数据
     *
     * @param ids {@link Long} 数据 id 集合
     * @return {@link List<TabErrorLog>} 结果集合
     */
    @Transactional(readOnly = true, propagation = Propagation.NOT_SUPPORTED)
    public @NotNull(message = "返回值不能为null") Map<Long, TabErrorLog> mapByIds(final Set<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyMap();
        }
        return repository.mapByIds(ids);
    }

}
